rm(list = ls(all = TRUE))
setwd("C:\\Users\\lenovo\\Desktop\\R")

#聚类分析中为无监督学习、判别分析为有监督学习

#收集训练样本和测试样本数据
#建立判别准则：选择方法、训练
#考核判别效果：回代法和前瞻法

#11.1 距离判别
#根据样本到各类中心点（均值向量）的距离，按距离最近准则判别
#因为马氏距离不受指标的量纲以及指标之间的多重相关性影响，所以最常用

#加载数据

data(iris)
cor(iris[,1:4])
#存在较强的正相关关系，马氏距离

#计算3种鸢尾花各指标的均值作为各个类别的中心点
m.setosa <- colMeans(iris[1:50,1:4])
m.setosa
m.versicolor <- colMeans(iris[51:100, 1:4])
m.versicolor
m.virginica <- colMeans(iris[101:150,1:4])
m.virginica

#需要考虑三种鸢尾花的4个指标的协方差矩阵是否相等
#Box'M检验
#install.packages("biotools")
library(biotools)
boxM(iris[,-5],iris[,5])
#Box‘M检验要求各变量符合多元正态分布
#零假设：各协方差矩阵相同
#现协方差矩阵差异有统计学意义，因此，分别计算3中类别下的协方差矩阵
v.setosa <- cov(iris[1:50,1:4])
v.setosa
v.versicolor <- cov(iris[51:100, 1:4])
v.versicolor
v.virginica <- cov(iris[101:150,1:4])
v.virginica

#用函数mahalanobis计算每个样品与3中鸢尾花的中心点的距离
#例如，计算第1个样品与3种鸢尾花数据中心点的马氏距离
mahalanobis(iris[1, 1:4], m.setosa, v.setosa)
mahalanobis(iris[1, 1:4], m.versicolor, v.versicolor)
mahalanobis(iris[1, 1:4], m.virginica, v.virginica)

#计算所有的样品
d.setosa <- mahalanobis(iris[, 1:4], m.setosa, v.setosa)
d.versicolor <- mahalanobis(iris[, 1:4], m.versicolor, v.versicolor)
d.virginica <- mahalanobis(iris[, 1:4], m.virginica, v.virginica)

#为便于比较，将上面3个向量放入一个数据框
d <- data.frame(d.setosa, d.versicolor, d.virginica)
head(d)

#对于数据框d的每一行数据，我们需要找出哪一行最小
#apply函数对矩阵或数据框按行（MARGIN=1）或者按列（MARGIN=2）执行某函数
#which.min用于找出最小值所在的位置

index <- apply(d, MARGIN = 1, FUN = which.min)
index

#上面的1、2、3分别代表不同的鸢尾花
#我们将它换成标签
type <- factor(index, labels = c("setosa", "versicolor","virginica"))
type

#借助判断类别与真实类别的列联表查看判别结果
#分类结果的混淆矩阵
table(type, iris$Species)

#量化判别结果的正确率与错误率为147/150=0.98

#找出这三个被错判的样本的编号
which(type == "virginica" & iris$Species == "versicolor")

#11.2 K最临近判别
#K-Nearest Neighbor,KNN算法是一个理论上比较成熟、也最简单的分类算法
#如果一个样品中的大多数属于某一个类别，那么该样品属于该类别
#主要依靠样品周围若干邻近样品的信息
#对于类域的交叉或重叠较多的待分类样品来说，分类效果更好

#建立训练集与测试集
set.seed(1234)
nrow(iris)
#抽100个样品作为训练集
s <- sample(1:150,100)
train <- iris[s,]
test <- iris[-s,]
#把训练集里样品的标签存为cl
cl <- train[,5]

#在knn函数中分别放入：
#训练集里的所有属性变量（除第5个变量Species）
#测试集（除第5个变量Species）
#训练集里的样品标签（cl，即训练集里的第5个变量Species）
#首先取邻近点的个数k为默认值1来进行判别

library(class)
iris.knn <- knn(train[,-5],test[,-5],cl)
iris.knn

#使用混淆矩阵查看判别结果
confushion.matrix <- table(iris.knn, test[,5])
confushion.matrix

#前瞻法判断的正确率
accuracy <- sum(diag(confushion.matrix))/nrow(test)
accuracy

#用for循环语句实现k从1-20的判别
accuracy <- vector(length = 20)
for (i in 1:20) {
  iris.knn <- knn(train[,-5],test[,-5],cl, k = i)
  confushion.matrix <- table(iris.knn,test[,5])
  accuracy[i] <- sum(diag(confushion.matrix))/nrow(test)
}
accuracy

#通过作图来直观获取正确率的大小
plot(accuracy, type = "b", xlab = "k")
#对于该数据集，当k取3-7时预测效果最佳，正确率达到98%

#此例中量纲一致，因此可以直接比较；
#当量纲差别较大时，需要先将属性变量标准化
#此外，当样品的类别不平衡，即，
#某些类别的样品很多，其他类别的样品很少时，knn算法可能并不稳定
#可以使用加权的K邻近（Weighted K-Nearest Neighbor）算法
#WKNN算法在KNN算法的基础上，对各已知类别的样本点
#根据其距离未知样本点的远近距离赋予不同的权重
#即，距离越近，权重越大
#一般来说，WKNN算法判别效果更优
#install.packages("kknn")
#kknn包中的kknn函数可以实现

#11.3 Fisher判别

#基本思想：投影
#将高维空间的样本点投影到低维空间，从而简化问题
#选择出适当的投影轴，保证投影后每一类之内的样本点的离散程度尽可能低
#不同类之间的样本点离散程度尽量高

#Fisher判别分为线性判别、二维判别等多种
#MASS包中的lda为线性判别、qda为二次判别

library(MASS)
iris.id <- lda(Species~Sepal.Length+Sepal.Width+
                 Petal.Length+Petal.Width, data = iris)
iris.id
#公式里，Species为因变量，其余四个变量为自变量
#先验概率的默认值为各个类别所占的比例

#将泛型函数predict用于线性判别对象可以得到各个样品的模型分类结果
iris.pred <- predict(iris.id)
iris.pred$class

#混淆矩阵
table(iris.pred$class, iris$Species)

#找出哪些样品被判错
which(iris.pred$class == "virginica" & iris$Species == "versicolor")
which(iris.pred$class == "versicolor" & iris$Species == "virginica")

#直观表示判别效果
LD1 <- iris.pred$x[,1]
LD2 <- iris.pred$x[,2]
col <- as.numeric(iris$Species)
pch <- as.numeric(iris$Species)
plot(LD1, LD2, col = col, pch = pch)
legend("top", legend = c("setosa", "versicolor","virginica"),
       col = 1:3, pch = 1:3)
#然后标注判别错误的点
points(LD1[c(71,84)], LD2[c(71,84)], cex = 2)
points(LD1[134], LD2[134], cex = 2)

#使用前瞻法：
#在predict里把参数newdata设置为测试集数据得到测试集里样品的判别分类
#并将此分类与测试集里样品的原始分类作比较

#11.4 Bayes判别

#假定对研究对象有一定的认识，这种认识用先验概率描述，
#再利用样本信息来修正已有的先验概率，从而得到后验概率
#最后根据后验概率判断样品的类别
#朴素Bayes分类是一种简单而实用的分类算法，基本原理为贝叶斯定理

#install.packages("klaR")
library(klaR)
iris.bayes <- NaiveBayes(Species ~Sepal.Length+Sepal.Width+
                           Petal.Length+Petal.Width, data = iris)
names(iris.bayes)
#apriori为先验概率；
#tables存储了用于建立判别规则的所有变量在各类别下的条件概率

#绘制参与规则建立的4个变量在不同类别鸢尾花下的密度曲线图
plot(iris.bayes)

#回代
iris.pred <- predict(iris.bayes)
table(iris.pred$class, iris$Species)

#决策树：rpart
#install.packages("rpart")

#随机森林：randomForest
#install.packages("randomForest")

#支持向量机：e1071，kernlab
#install.packages("e1071")
#install.packages("kernlab")

#人工神经网络：nnet，neuralnet
#install.packages("nnet")
#install.packages("neuralnet")


